/*
 * Copyright (C) 2007-2008  Hylke van der Schaaf
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, in version 3 of the License.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package hextd;

import com.twolattes.json.Entity;
import com.twolattes.json.Json;
import com.twolattes.json.Marshaller;
import com.twolattes.json.TwoLattes;
import com.twolattes.json.Value;
import java.util.HashMap;
import java.util.Map.Entry;

@Entity
public class Keymap {

	public static enum MappableAction {

		startTextInput,
		makeHexEmpty,
		makeHexNormal,
		makeHexTransparent,
		makeHexPath,
		buyCreeps,
		fastForwardToggle,
		fastForwardUp,
		fastForwardDown,
		callNextWave,
		pauseToggle,
		confirm,
		sellSelectedTower,
		targetModeUp,
		targetModeDown,
		toggleLock,
		upgrade,
		upgradeFull,
		creepCountToggle,
		creepCountUp,
		creepCountDown,
		creepSizeUp,
		creepSizeDown,
		creepHealthUp,
		creepHealthDown,
		creepTypeUp,
		creepTypeDown,
		pathUp,
		pathDown,
		buildTowerGreen1,
		buildTowerGreen2,
		buildTowerGreen3,
		buildTowerRed1,
		buildTowerRed2,
		buildTowerRed3,
		buildTowerYellow1,
		buildTowerYellow2,
		buildTowerYellow3,
		buildTowerBlue1,
		buildTowerBlue2,
		buildTowerBlue3,
		buildTowerRange,
		buildTowerDamage,
		buildTowerControl,
		cancel
	}

	public static enum MappableGameState {

		playing,
		editing,
		watching
	}
	/**
	 * returns the default keymap
	 * @return the default keymap
	 */
	public static HashMap<MappableGameState, HashMap<Character, MappableAction>> getDefaultKeymap() {
		HashMap<MappableGameState, HashMap<Character, MappableAction>> table = new HashMap<MappableGameState, HashMap<Character, MappableAction>>();

		HashMap<Character, MappableAction> stateTable = new HashMap<Character, MappableAction>();
		stateTable.put('r', MappableAction.buildTowerBlue1);
		stateTable.put('f', MappableAction.buildTowerBlue2);
		stateTable.put('v', MappableAction.buildTowerBlue3);
		//stateTable.put('', MappableAction.buildTowerControl);
		//stateTable.put('', MappableAction.buildTowerDamage);
		stateTable.put('q', MappableAction.buildTowerGreen1);
		stateTable.put('a', MappableAction.buildTowerGreen2);
		stateTable.put('z', MappableAction.buildTowerGreen3);
		//stateTable.put('', MappableAction.buildTowerRange);
		stateTable.put('w', MappableAction.buildTowerRed1);
		stateTable.put('s', MappableAction.buildTowerRed2);
		stateTable.put('x', MappableAction.buildTowerRed3);
		stateTable.put('e', MappableAction.buildTowerYellow1);
		stateTable.put('d', MappableAction.buildTowerYellow2);
		stateTable.put('c', MappableAction.buildTowerYellow3);
		stateTable.put(' ', MappableAction.buyCreeps);
		stateTable.put('n', MappableAction.callNextWave);
		stateTable.put('', MappableAction.cancel);
		stateTable.put('y', MappableAction.confirm);
		stateTable.put('1', MappableAction.creepCountDown);
		stateTable.put('2', MappableAction.creepCountUp);
		stateTable.put('`', MappableAction.creepCountToggle);
		stateTable.put('3', MappableAction.creepHealthDown);
		stateTable.put('4', MappableAction.creepHealthUp);
		stateTable.put('5', MappableAction.creepSizeDown);
		stateTable.put('6', MappableAction.creepSizeUp);
		stateTable.put('7', MappableAction.creepTypeDown);
		stateTable.put('8', MappableAction.creepTypeUp);
		stateTable.put('-', MappableAction.fastForwardDown);
		stateTable.put('h', MappableAction.fastForwardToggle);
		stateTable.put('+', MappableAction.fastForwardUp);
		stateTable.put(',', MappableAction.pathDown);
		stateTable.put('.', MappableAction.pathUp);
		stateTable.put('p', MappableAction.pauseToggle);
		stateTable.put('S', MappableAction.sellSelectedTower);
		stateTable.put('T', MappableAction.targetModeDown);
		stateTable.put('t', MappableAction.targetModeUp);
		stateTable.put('l', MappableAction.toggleLock);
		stateTable.put('u', MappableAction.upgrade);
		stateTable.put('U', MappableAction.upgradeFull);
		stateTable.put('b', MappableAction.startTextInput);
		table.put(MappableGameState.playing, stateTable);

		stateTable = new HashMap<Character, MappableAction>();
		stateTable.put('-', MappableAction.fastForwardDown);
		stateTable.put('h', MappableAction.fastForwardToggle);
		stateTable.put('+', MappableAction.fastForwardUp);
		stateTable.put('p', MappableAction.pauseToggle);
		table.put(MappableGameState.watching, stateTable);

		stateTable = new HashMap<Character, MappableAction>();
		stateTable.put('e', MappableAction.makeHexEmpty);
		stateTable.put('n', MappableAction.makeHexNormal);
		stateTable.put('p', MappableAction.makeHexPath);
		stateTable.put('t', MappableAction.makeHexTransparent);
		table.put(MappableGameState.editing, stateTable);

		return table;
	}
	// Keymap that is used during play
	private HashMap<MappableGameState, HashMap<Character, MappableAction>> keyMapRuntime;
	// Keymap that can be stored as JSon
	@Value
	public HashMap<String, HashMap<String, MappableAction>> keyMap;

	public Keymap() {
	}

	public MappableAction getAction(MappableGameState state, char key) {
		if (keyMapRuntime == null) {
			keyMapRuntime = getDefaultKeymap();
		}
		HashMap<Character, MappableAction> get = keyMapRuntime.get(state);
		if (get != null) {
			return get.get(key);
		}
		return null;
	}

	public void setKeyMap(HashMap<MappableGameState, HashMap<Character, MappableAction>> keyMap) {
		keyMapRuntime = keyMap;
		this.keyMap = null;
	}

	public static Keymap loadKeyMap(String mapJson) {
		Keymap newKeyMap = null;
		Marshaller<Keymap> marshaller = TwoLattes.createMarshaller(Keymap.class);
		try {
			Json.Value fromString = Json.fromString(mapJson);
			newKeyMap = marshaller.unmarshall((Json.Object) fromString);
			newKeyMap.parseKeymap();
		} catch (ClassCastException e) {
			System.out.println("MapInfo::getMapData: Not a valid JSon keymap!");
		} catch (IllegalArgumentException e) {
			System.out.println("MapInfo::getMapData: Not a valid JSon keymap!");
		}

		if (newKeyMap == null) {
			newKeyMap = new Keymap();
		}
		return newKeyMap;
	}

	private void parseKeymap() {
		keyMapRuntime = new HashMap<MappableGameState, HashMap<Character, MappableAction>>();
		for (Entry<String, HashMap<String, MappableAction>> e1 : keyMap.entrySet()) {
			HashMap<Character, MappableAction> tempTable = new HashMap<Character, MappableAction>();
			for (Entry<String, MappableAction> e2 : e1.getValue().entrySet()) {
				tempTable.put(e2.getKey().charAt(0), e2.getValue());
			}
			keyMapRuntime.put(MappableGameState.valueOf(e1.getKey()), tempTable);
		}
	}

	public String printKeymap() {
		if (keyMapRuntime == null) {
			keyMapRuntime = getDefaultKeymap();
		}
		if (keyMap == null) {
			keyMap = new HashMap<String, HashMap<String, MappableAction>>();
			for (Entry<MappableGameState, HashMap<Character, MappableAction>> e1 : keyMapRuntime.entrySet()) {
				HashMap<String, MappableAction> tempTable = new HashMap<String, MappableAction>();
				for (Entry<Character, MappableAction> e2 : e1.getValue().entrySet()) {
					tempTable.put(e2.getKey().toString(), e2.getValue());
				}
				keyMap.put(e1.getKey().name(), tempTable);
			}
		}
		Marshaller<Keymap> marshaller = TwoLattes.createMarshaller(Keymap.class);
		Object marshall = marshaller.marshall(this);
		return marshall.toString();
	}
}
